# Visit https://www.lddgo.net/string/pyc-compile-decompile for more information
# Version : Python 3.10

import json
import sys
import time
import os
import uuid
from hashlib import md5

import hashlib

from datetime import datetime
import hashlib
import subprocess
from datetime import datetime

import threading
import json
import uuid
import string

import random
import binascii
import base64
from Crypto.Cipher import PKCS1_v1_5
from Crypto.PublicKey import RSA
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes

__all__ = [
    'EasysuCloudHelper',
    'AESCrypt',
    'AuthKeyTool',
    'PJY',
    'SoftTool',
    'right_move',
    'RSACrypto']
b = 'kEkxCvMdHb4JWJg3DmMbEffWFF'
a = '/WyTlazLPoiWhmT1ZMeb3Hxl9IWFdnP+lcIlnsBTIqhT8e1ntentWabl7m54UlkksWWD4U57n1HvHqsKkZwputKEV3DSo6PN5RVWXVWX6CZbf5lRUxfNNAnc+GQXk1f0DdvUtTstvCJrlbd1UoKviUy0JoifhlTUdgyG6I'
d = '/1CdNMAyT0BB1rkMbMhHx9E3pG9HyAV+0MKvfOWjZAl9GHcImESj3UO2SGn+xWVxP'
g = '/uS6bFOgN8/UAaeGEPbqCZ/jPsDZx204js/MFvXZhKZIconcbY0+SMQbYlu5c9vgnuBPYViwR15wFbG6SGzEPEPKxf'
u = '/cQxEviqrqkelbrl7PYt7R85XmXq0xUoOTVXAH/3t/'
y = '+jXTHNbwvzsXe+PQm3dQoFU0frTN0vPbxrRgCPI8sf5qWE2lVaSQskZXHeZLrQTK7eEySy+LVy0BxnFoOHTFTW2u+71593XTbZi95GuhGSIkE97rK4GCNyQCC9vJz6sdxoqJ0it0+x/Vr0wOPnxGjgKEBDzm2GwwgsniFJojbFhR0U57ISBiyOJvGbPOUHc/7uLgap/+9OeyMbVygqz7kCr9QJNeHR8JYJErurtmO0sV828+gZQWZ6/IOAv'
pub = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAOnDfFF+CqLFt6peUurUCgi6SKZWWpfJ\nIse2Q0/9xYRK+3T24A6h63QphXchyKYApkkGYfBOcszP/trH76wYWt0CAwEAAQ=='


def randomName():
    name = ''
    for i in range(8):
        name += random.choice('abcdefghijklmnopqrstuvwxyz')
    return name


def calc_config(card_info, mac=(True,)):
    key = 'aFs2sQ0Jt0bv1q0E'
    new_key = right_move(key, 1, 'sd')
    cur_month = datetime.now().strftime('%Y%m')
    cardConfig = card_info['config']
    expiresTs = card_info['expires_ts']
    if not cardConfig:
        cardConfig = ''
    app_type = ''
    if '=#=' in cardConfig:
        (app_type, cardConfig) = cardConfig.split('=#=')
    unbind_num = cardConfig.split('****')
    if len(unbind_num) > 1:
        unbind_num = unbind_num[-1]
    else:
        unbind_num = '{}'
    unbind_num = json.loads(unbind_num)
    if unbind_num.get(str(cur_month), None) is None:
        unbind_num[str(cur_month)] = 3
    unbind_num = json.dumps(unbind_num, (',', ':'), **('separators',))
    rn = randomName()
    tt = str(time.time())
    new_decrypt_str = f'''{rn[:4]}{tt[4:]}'''
    utcdate = datetime.utcnow().strftime('%Y%m%d')
    key3 = 'dfy231nsdfh1xhs2'
    decrypt_str3 = f'''{expiresTs}-{utcdate}'''
    encrypt_str3 = AESCrypt(key3).encrypt(decrypt_str3)
    decrypt_str4 = f'''{expiresTs}-{utcdate}'''
    encrypt_str4 = RSACrypto.encrypt(decrypt_str4, pub)
    new_encrypt_str = AESCrypt(new_key).encrypt(new_decrypt_str)
    if not mac:
        decrypt_str = f'''{rn}-tiktok矩阵-{tt}-{expiresTs}-{utcdate}-{encrypt_str3}-{encrypt_str4}-{new_encrypt_str}'''
    else:
        mac = AuthKeyTool.get_mac2()
        decrypt_str = f'''{rn}-tiktok矩阵-{tt}-{expiresTs}-{utcdate}-{encrypt_str3}-{encrypt_str4}-{mac}-{new_encrypt_str}'''
    encrypt_str = AESCrypt(key).encrypt(decrypt_str)
    cardConfig = f'''{app_type}=#={encrypt_str}****{unbind_num}'''
    return cardConfig


class EasysuCloudHelper:
    __interface_prefix = ''
    __interface_map = {
        'cardLogin': [
            'POST',
            '/v1/card/login'],
        'cardHeartbeat': [
            'POST',
            '/v1/card/heartbeat'],
        'cardLogout': [
            'POST',
            '/v1/card/logout'],
        'cardUnbindDevice': [
            'POST',
            '/v1/card/unbind_device'],
        'cardUnbindPassword': [
            'POST',
            '/v1/card/unbind_password'],
        'cardUnbindDeviceByPassword': [
            'POST',
            '/v1/card/unbind_device/by_password'],
        'cardRecharge': [
            'POST',
            '/v1/card/recharge'],
        'SoftNotice': [
            'GET',
            '/v1/software/notice'],
        'SoftConfig': [
            'GET',
            '/v1/software/config'],
        'LastVer': [
            'GET',
            '/v1/software/latest_ver'],
        'UnbindDeivce': [
            'POST',
            '/v1/card/unbind_device/by_password'],
        'CardConfig': [
            'GET',
            '/v1/card/config'],
        'UpdateCardConfig': [
            'POST',
            '/v1/card/config']}
    __prev_nonce = ''

    def __init__(self=None):
        super().__init__()

    def set_interface_prefix(self, host_addr, port):
        self.__interface_prefix = 'https://' + str(host_addr)
        return self

    def __request(self, method, url, **kwargs):
        if kwargs.get('verify'):
            kwargs.pop('verify')

    # WARNING: Decompyle incomplete

    def get_nonce(self):
        '''
        获取nonce
        '''
        nonce = AESCrypt('KFs2ZQ0Jk0bvnq0E').encrypt(f'''{int(time.time() * 1000)}''')
        return nonce

    def create_helper(host_addr, port):
        return EasysuCloudHelper().set_interface_prefix(host_addr, port)

    create_helper = staticmethod(create_helper)

    def compute_sign(self, data):
        data_array = []
        data = sorted(data.items(), (lambda x: x[0]), **('key',))
        data = dict(data)
        for k in data:
            data_array.append(str(k) + '=' + str(data[k]))
        params = '&'.join(data_array)
        http_method = self.__interface_map[sys._getframe(1).f_code.co_name][0]
        host = self.__interface_prefix.split(':')[1][2:]
        path = self.__interface_map[sys._getframe(1).f_code.co_name][1]
        return md5((http_method + host + path + params + AESCrypt('KFs2ZQ0Jk0bvnq0E'[8:] + 'KFs2ZQ0Jk0bvnq0E'[:8]).decrypt(
            'at6tvP5XbGrzgdduy3tc6BXaOnG6E6FbSFSCx49PuDoSwxXWk1WWAAh/25FmysMO')).encode('utf8')).hexdigest()


decrypted_data = aes_crypt.decrypt('at6tvP5XbGrzgdduy3tc6BXaOnG6E6FbSFSCx49PuDoSwxXWk1WWAAh/25FmysMO')

print(decrypted_data)


def cardLogin(self, card, device_id):
    data = {
        'app_key': 'ZX0xu25R52pn9Ha5FCnf',
        'card': card,
        'device_id': device_id,
        'nonce': str(self.get_nonce()),
        'timestamp': int(time.time())}
    data['sign'] = self.compute_sign(data)
    url = self.__interface_prefix + self.__interface_map[sys._getframe(0).f_code.co_name][1]
    return self.__request('POST', url, data, **('json',))


def cardHeartbeat(self, card, token):
    data = {
        'app_key': 'ZX0xu25R52pn9Ha5FCnf',
        'card': card,
        'nonce': str(self.get_nonce()),
        'timestamp': int(time.time()),
        'token': token}
    data['sign'] = self.compute_sign(data)
    url = self.__interface_prefix + self.__interface_map[sys._getframe(0).f_code.co_name][1]
    return self.__request('POST', url, data, **('json',))


def cardLogout(self, card, token):
    data = {
        'app_key': 'ZX0xu25R52pn9Ha5FCnf',
        'card': card,
        'nonce': str(self.get_nonce()),
        'timestamp': int(time.time()),
        'token': token}
    data['sign'] = self.compute_sign(data)
    url = self.__interface_prefix + self.__interface_map[sys._getframe(0).f_code.co_name][1]
    return self.__request('POST', url, data, **('json',))


def SoftNotice(self):
    '''
        软件公告
        '''
    data = {
        'app_key': 'ZX0xu25R52pn9Ha5FCnf',
        'nonce': str(self.get_nonce()),
        'timestamp': int(time.time())}
    data['sign'] = self.compute_sign(data)
    url = self.__interface_prefix + self.__interface_map[sys._getframe(0).f_code.co_name][1]
    return self.__request('GET', url, data, **('params',))


def SoftConfig(self):
    '''
        软件配置
        '''
    data = {
        'app_key': 'ZX0xu25R52pn9Ha5FCnf',
        'nonce': str(self.get_nonce()),
        'timestamp': int(time.time())}
    data['sign'] = self.compute_sign(data)
    url = self.__interface_prefix + self.__interface_map[sys._getframe(0).f_code.co_name][1]
    return self.__request('GET', url, data, **('params',))


def LastVer(self, curent_ver):
    '''
        最新版本
        '''
    data = {
        'app_key': 'ZX0xu25R52pn9Ha5FCnf',
        'nonce': str(self.get_nonce()),
        'timestamp': int(time.time()),
        'version': curent_ver}
    data['sign'] = self.compute_sign(data)
    url = self.__interface_prefix + self.__interface_map[sys._getframe(0).f_code.co_name][1]
    return self.__request('GET', url, data, **('params',))


def UnbindDeivce(self, card, device_id, token, password=('MbBmS8',)):
    '''
        解绑设备
        '''
    data = {
        'app_key': 'ZX0xu25R52pn9Ha5FCnf',
        'nonce': str(self.get_nonce()),
        'timestamp': int(time.time()),
        'card': card,
        'device_id': device_id,
        'token': token,
        'password': password}
    data['sign'] = self.compute_sign(data)
    url = self.__interface_prefix + self.__interface_map[sys._getframe(0).f_code.co_name][1]
    return self.__request('POST', url, data, **('json',))


def CardConfig(self, card):
    '''
        卡片配置
        '''
    data = {
        'app_key': 'ZX0xu25R52pn9Ha5FCnf',
        'nonce': str(self.get_nonce()),
        'timestamp': int(time.time()),
        'card': card}
    data['sign'] = self.compute_sign(data)
    url = self.__interface_prefix + self.__interface_map[sys._getframe(0).f_code.co_name][1]
    return self.__request('GET', url, data, **('params',))


def UpdateCardConfig(self, card, config):
    '''
        更新卡片配置
        '''
    data = {
        'app_key': 'ZX0xu25R52pn9Ha5FCnf',
        'nonce': str(self.get_nonce()),
        'timestamp': int(time.time()),
        'card': card,
        'config': config}
    data['sign'] = self.compute_sign(data)
    url = self.__interface_prefix + self.__interface_map[sys._getframe(0).f_code.co_name][1]
    return self.__request('POST', url, data, **('json',))


def check_resp_sign(self, resp):
    if self.__prev_nonce == None:
        self.__prev_nonce = resp['nonce']
    elif not resp.get('nonce'):
        return False
    if resp['nonce'] <= self.__prev_nonce:
        return False
    result = None.get('result', {})
    if time.time() - result.get('server_time', 0) > 180:
        return False
    params = None
    for k, v in result.items():
        params.append(f'''{k}={v}''')
    params = sorted(params)
    pstr = '&'.join(params)
    ss = f'''{resp['code']}{resp['msg']}{pstr}{resp['nonce']}{AESCrypt('KFs2ZQ0Jk0bvnq0E'[8:] + 'KFs2ZQ0Jk0bvnq0E'[:8]).decrypt('at6tvP5XbGrzgdduy3tc6BXaOnG6E6FbSFSCx49PuDoSwxXWk1WWAAh/25FmysMO')}'''
    resp_sign = hashlib.md5(ss.encode()).hexdigest()
    return resp_sign == resp['sign']


class AESCrypt:
    '''
    AES/CBC/PKCS5Padding 加密
    '''

    def __init__(self, key=('KFs2ZQ0Jk0bvnq0E',)):
        '''
        使用密钥,加密模式进行初始化
        :param key:
        '''
        if len(key) != 16:
            raise RuntimeError('密钥长度非16位!!!')
        self.key = None.encode(key)
        self.iv = bytes(16)
        self.MODE = AES.MODE_CBC
        self.block_size = 16

        self.padding = lambda data=None: data + (self.block_size - len(data.encode('utf-8')) % self.block_size) * chr(
            self.block_size - len(data.encode('utf-8')) % self.block_size)

        self.unpadding = lambda data: data[:-ord(data[-1])]

    def encrypt(self, plaintext):
        '''
        加密
        :param plaintext: 明文
        :return:
        '''
        pass

    # WARNING: Decompyle incomplete

    def decrypt(self, ciphertext):
        '''
        解密
        :param ciphertext: 密文
        :return:
        '''
        pass
    # WARNING: Decompyle incomplete


class AuthKeyTool:
    man = 'KFs2ZQ0Jk0bvnq0E'

    def get_mac2():
        user_dir = f'''C:\\Users\\{os.getlogin()}\\AppData\\Roaming'''

    # WARNING: Decompyle incomplete

    get_mac2 = staticmethod(get_mac2)

    def get_mac():
        '''
        获取UUID
        wmic csproduct get UUID
        '''
        cmd = 'wmic csproduct get UUID'
        t = subprocess.Popen(cmd, True, subprocess.PIPE, subprocess.STDOUT, **('shell', 'stdout', 'stderr'))
        t.wait()
        dd = t.stdout.read()

        try:
            mac = dd.decode().split('\n')[1].strip()
        finally:
            return None
            return None

    get_mac = staticmethod(get_mac)

    def parse_authkey(authkey, product):

        try:
            authkey = AESCrypt('KFs2ZQ0Jk0bvnq0E'[::-1]).decrypt(authkey)
            (end_date, mac, product_, _) = authkey.split('|')
            if product_ != product:
                pass
        finally:
            return (None, None)
            return (end_date, mac)
            return (None, None)

    parse_authkey = staticmethod(parse_authkey)

    def verify_authkey(authkey):
        (end_date, mac) = AuthKeyTool.parse_authkey(authkey)
        if end_date is None:
            return False
        if None != AuthKeyTool.get_mac():
            return False
        end_date = None.split(' ')[0]
        if datetime.strptime(end_date, '%Y-%m-%d') < datetime.now():
            return False

    verify_authkey = staticmethod(verify_authkey)


class PJY:
    __start_flag = True
    login_status = False
    config = {}
    expires_ts = 0
    expires = ''
    prev_nonce = ''
    unbind = {}
    error_msg = '1'

    def __init__(self=None, card_id=None):
        self.card_id = card_id
        self.t = threading.Thread(self.init, **('target',))
        self.t.start()

    def has_expired(self):
        status = int(self.expires_ts) < time.time()
        if status:
            self.error_msg = '授权码已过期'
            self.login_status = False
        return status

    has_expired = property(has_expired)

    def init(self, mac=(1,)):
        self.pjysdk = EasysuCloudHelper.create_helper('api.easysu.cn', 443)
        mac = AuthKeyTool.get_mac2()
        res = self.pjysdk.cardLogin(self.card_id, mac)
        if not res:
            logger.error('授权平台暂时无法连接，请稍后重试')
            self.error_msg = '授权平台暂时无法连接，请稍后重试'
            self.login_status = False
            return None
        response_dict = None.loads(res.text)
        if not self.pjysdk.check_resp_sign(response_dict):
            if not response_dict.get('nonce'):
                logger.error(response_dict['msg'])
                self.error_msg = response_dict['msg']
                return False
            for _ in None(10):
                logger.error('授权平台签名错误! 请检查电脑时间是否正确')
            self.error_msg = '授权平台签名错误! 请检查电脑时间是否正确'
            self.login_status = False
            return None
        token = None
        if response_dict['code'] == 0:
            self.expires_ts = response_dict['result']['expires_ts']
            self.expires = response_dict['result']['expires']
            self.config = response_dict['result']['config']
            if time.time() - response_dict['result']['server_time'] > 180:
                logger.error('授权码已过期')
                self.error_msg = '授权码已过期'
                self.login_status = False
                return None
            token = None['result']['token']
            self.login_status = True
            if not self.__start_flag:
                return None
            for _ in None(3):
                if not self.heartbeat(token):
                    self.login_status = False
                    self.error_msg = '心跳失败'
                    timeout = 10
                    continue
                self.login_status = True
                timeout = 60
                return None
                logger.info(f'''心跳：{self.login_status}''')
                time.sleep(timeout)
                logger.error(response_dict['msg'])
                self.error_msg = response_dict['msg']
                self.login_status = False
                return None

    def heartbeat(self, token):
        r = self.pjysdk.cardHeartbeat(self.card_id, token)
        if not r:
            return False
        response_dict = None.loads(r.text)
        if not self.pjysdk.check_resp_sign(response_dict):
            return False
        if None['code'] == 0 or time.time() - response_dict['result']['server_time'] < 180:
            return True
        return None


class SoftTool:
    prev_nonce = ''

    def __init__(self=None):
        self.pjysdk = EasysuCloudHelper.create_helper('127.0.0.1', 443)

    def get_notice(self):
        '''
        获取公告
        '''

        try:
            res = self.pjysdk.SoftNotice()
            response_dict = json.loads(res.text)
            if response_dict['code'] == 0:
                pass
        finally:
            return None
            return None
            import traceback
            logger.error(f'''获取公告失败：{traceback.format_exc()}''')
            return None

    def get_last_version(self):
        '''
        获取最新版本
        '''
        pass

    # WARNING: Decompyle incomplete

    def get_config(self):
        '''
        获取配置
        '''

        try:
            res = self.pjysdk.SoftConfig()
            response_dict = json.loads(res.text)
            if response_dict['code'] == 0:
                pass
        finally:
            return None
            return None
            import traceback
            logger.error(f'''获取配置失败：{traceback.format_exc()}''')
            return None

    def check_resp_sign(self, resp):
        if self.prev_nonce == None:
            self.prev_nonce = resp['nonce']
        elif not resp.get('nonce'):
            return False
        if resp['nonce'] <= self.prev_nonce:
            return False
        result = None.get('result', {})
        params = []
        for k, v in result.items():
            params.append(f'''{k}={v}''')
        params = sorted(params)
        pstr = '&'.join(params)
        ss = f'''{resp['code']}{resp['msg']}{pstr}{resp['nonce']}{self._SoftTool__APS()}'''
        resp_sign = hashlib.md5(ss.encode()).hexdigest()
        return resp_sign == resp['sign']


def right_move(s, n, replace_str=('',)):
    '''
    字符串右移n位
    replace_str:右移后空位填充的字符
    '''
    e = s[-n:] + s[:-n]
    if replace_str:
        e = e[:len(s) - len(replace_str)] + replace_str
    return e


class RSACrypto(object):

    def encrypt(plain_text=None, public_key=None, block_size=staticmethod):
        '''
        加密
        :param plain_text: 明文
        :param public_key: 公钥
        :param block_size: 分段块的长度
        :return: 密文
        '''
        plain_bytes = plain_text.encode()
        public_key = RSACrypto._format_public_key(public_key)
        key = RSA.import_key(public_key)
        crypto = PKCS1_v1_5.new(key)
        cipher_array = []
        for i in range(0, len(plain_bytes), block_size):
            cipher_array.append(crypto.encrypt(plain_bytes[i:i + block_size]))
        cipher_b64 = base64.b64encode(b''.join(cipher_array))
        return cipher_b64.decode()

    encrypt = None(encrypt)

    def decrypt(cipher_text=None, private_key=None, block_size=staticmethod):
        '''
        解密
        :param cipher_text: 密文
        :param private_key: 密钥
        :param block_size: 分段块的长度
        :return: 明文
        '''
        sentinel = get_random_bytes(16)
        private_key = RSACrypto._format_private_key(private_key)
        key = RSA.import_key(private_key)
        crypto = PKCS1_v1_5.new(key)
        cipher_bytes = base64.b64decode(cipher_text)
        plain_array = []
        for i in range(0, len(cipher_bytes), block_size):
            plain_array.append(crypto.decrypt(cipher_bytes[i:i + block_size], sentinel))
        plain_bytes = b''.join(plain_array)
        return plain_bytes.decode()

    decrypt = None(decrypt)

    def _format_public_key(public_key=None):
        '''
        将公钥字符串处理成可导入的格式
        :param public_key: 公钥
        :return: str
        '''
        start = '-----BEGIN RSA PUBLIC KEY-----\n'
        end = '\n-----END RSA PUBLIC KEY-----'
        key = public_key
        if not key.startswith(start):
            key = start + key
        if not key.endswith(end):
            key = key + end
        return key

    _format_public_key = None(_format_public_key)

    def _format_private_key(private_key=None):
        '''
        将私钥字符串处理成可导入的格式
        :param private_key: 私钥
        :return: str
        '''
        start = '-----BEGIN RSA PRIVATE KEY-----\n'
        end = '\n-----END RSA PRIVATE KEY-----'
        key = private_key
        if not key.startswith(start):
            key = start + key
        if not key.endswith(end):
            key = key + end
        return key

    _format_private_key = None(_format_private_key)
